package com.zh.systemUtils;


import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;


public class SystemUtils {
    private final static float TotalBandwidth = 80; //设定带宽，Mbps

    public static ResourceUsageInfoBean infoBean;

    private SystemUtils() {
        this.infoBean = new ResourceUsageInfoBean();
    }

    /**
     * Purpose:采集CPU使用率
     * 兼容多核
     *
     * @return
     */
    public ResourceUsageInfoBean getCpuUsage() {
        float cpuUsage = 0;
        Process pro1 = null, pro2 = null;
        Runtime r = Runtime.getRuntime();
        BufferedReader in1 = null, in2 = null;
        try {
            String command = "cat /proc/stat";

            //第一次采集CPU时间
            pro1 = r.exec(command);
            in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long idleCpuTime1 = 0, totalCpuTime1 = 0;    //分别为系统启动后空闲的CPU时间和总的CPU时间
            while ((line = in1.readLine()) != null) {
                if (line.startsWith("cpu")) {
                    line = line.trim();
                    String[] temp = line.split("\\s+");
                    idleCpuTime1 = Long.parseLong(temp[4]);
                    for (String s : temp) {
                        if (!s.equals("cpu")) {
                            totalCpuTime1 += Long.parseLong(s);
                        }
                    }
                    break;
                }
            }

            //第二次采集CPU时间
            Thread.sleep(100);

            pro2 = r.exec(command);
            in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long idleCpuTime2 = 0, totalCpuTime2 = 0;    //分别为系统启动后空闲的CPU时间和总的CPU时间
            while ((line = in2.readLine()) != null) {
                if (line.startsWith("cpu")) {
                    line = line.trim();
                    String[] temp = line.split("\\s+");
                    idleCpuTime2 = Long.parseLong(temp[4]);
                    for (String s : temp) {
                        if (!s.equals("cpu")) {
                            totalCpuTime2 += Long.parseLong(s);
                        }
                    }
                    //System.out.println("IdleCpuTime: " + idleCpuTime2 + ", " + "TotalCpuTime" + totalCpuTime2);
                    break;
                }
            }
            if (idleCpuTime1 != 0 && totalCpuTime1 != 0 && idleCpuTime2 != 0 && totalCpuTime2 != 0) {
                cpuUsage = 1 - (float) (idleCpuTime2 - idleCpuTime1) / (float) (totalCpuTime2 - totalCpuTime1);
                cpuUsage = formatFloat(cpuUsage);
                System.out.println("CPU使用率: " + formatFloat(cpuUsage * 100) + "%");
                infoBean.setCpuUsage(formatFloat(cpuUsage));//赋值！！
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(in1, in2);
            IOUtils.close(pro1, pro2);
        }
        return infoBean;
    }


    /**
     * Purpose:采集内存及Swap的数据封装入bean属性
     *
     * @return bean
     */
    public ResourceUsageInfoBean getMemoryUsage() {
        float memUsage = 0.0f;
        float swapUsage = 0.0f;
        Process pro = null;
        Runtime runtime = Runtime.getRuntime();
        BufferedReader in = null;
        try {
            String command = "cat /proc/meminfo";
            pro = runtime.exec(command);
            in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;

            long totalMem = 0, freeMem = 0;
            long totalSwap = 0, freeSwap = 0;
            while ((line = in.readLine()) != null) {
                //System.out.println(line);
                String[] memInfo = line.split("\\s+");
                if (memInfo[0].startsWith("MemTotal")) {
                    totalMem = Long.parseLong(memInfo[1]);
                }
                if (memInfo[0].startsWith("MemFree")) {
                    freeMem = Long.parseLong(memInfo[1]);
                }
                memUsage = 1 - (float) freeMem / (float) totalMem;
                if (memInfo[0].startsWith("SwapTotal")) {
                    totalSwap = Long.parseLong(memInfo[1]);
                }
                if (memInfo[0].startsWith("SwapFree")) {
                    freeSwap = Long.parseLong(memInfo[1]);
                }
                swapUsage = 1 - (float) freeSwap / (float) totalSwap;
                if (totalMem != 0 && totalSwap != 0 && freeMem != 0 && freeSwap != 0) {
                    System.out.println("内存总量： " + totalMem / 1024 + " MB");
                    System.out.println("内存空闲： " + freeMem / 1024 + " MB");
                    System.out.println("内存使用率: " + formatFloat(memUsage * 100) + "%");
                    infoBean.setMemoryTotal(totalMem);
                    infoBean.setMemoryfree(freeMem);
                    infoBean.setMemoryUsage(formatFloat(memUsage));
                    System.out.println("Swap总量： " + totalSwap / 1024 + " MB");
                    System.out.println("Swap空闲： " + freeSwap / 1024 + " MB");
                    System.out.println("Swap使用率: " + formatFloat(swapUsage * 100) + "%");
                    infoBean.setSwapTotal(totalSwap);
                    infoBean.setSwapfree(freeSwap);
                    infoBean.setSwapUsage(formatFloat(swapUsage));
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(in);
            IOUtils.close(pro);
        }
        return infoBean;
    }

    /**
     * @return bean
     * %util： 在统计时间内所有处理IO时间，除以总共统计时间。例如，如果统计间隔1秒，该设备有0.8
     * 秒在处理IO，而0.2秒闲置，那么该设备的%util = 0.8/1 = 80%，所以该参数暗示了设备的繁忙程度
     * @Purpose :采集磁盘IO使用率
     * IO使用率体现的是使用率最高的分区
     */
    public ResourceUsageInfoBean getIOUsage() {
        float ioUsage = 0.0f;
        Process pro = null;
        BufferedReader in = null;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "iostat -d -x";
            pro = r.exec(command);
            in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;
            int count = 0;
            List<String> infoIO = new ArrayList<String>();
            List<DiskNode> infoDiskNode = new ArrayList<DiskNode>();
            while ((line = in.readLine()) != null) {
                if (count == 0) {
                    String[] ioInfo = line.split("\\s+");
                    infoBean.setLinuxCoreVersion(ioInfo[0] + " " + ioInfo[1]);
                    String temp2 = ioInfo[2];
                    infoBean.setHostNameFromIOCommand(temp2.substring(1, temp2.length() - 1));
                    infoBean.setSystemTimeInChinese(ioInfo[3]);
                    infoBean.setSystemType(ioInfo[4].substring(1, ioInfo[4].length() - 1));
                    infoBean.setCoreNum(Byte.valueOf(ioInfo[5].substring(1, ioInfo[5].length())));

                    System.out.println("系统版本: " + infoBean.getLinuxCoreVersion());
                    System.out.println("hostname: " + infoBean.getHostNameFromIOCommand());
                    System.out.println("系统位数: " + infoBean.getSystemType());
                    System.out.println("系统核心数量: " + infoBean.getCoreNum());
                    System.out.println("中文格式系统时间: " + infoBean.getSystemTimeInChinese());
                }
                if (count++ >= 3) {//格式数
                    String[] temp = line.split("\\s+");
                    if (temp.length > 1) {
                        float util = Float.parseFloat(temp[temp.length - 1]);
                        ioUsage = (ioUsage > util) ? ioUsage : util;
                        DiskNode diskNode = new DiskNode();
                        diskNode.setDevice(temp[0]);
                        diskNode.setRrqmS(Float.valueOf(temp[1]));
                        diskNode.setWrqmS(Float.valueOf(temp[2]));
                        diskNode.setrS(Float.valueOf(temp[3]));
                        diskNode.setwS(Float.valueOf(temp[4]));
                        //diskNode.setRkBs(Float.valueOf(temp[5]));
                        diskNode.setRsecS(Float.valueOf(temp[5]));
                        //diskNode.setWkBs(Float.valueOf(temp[6]));
                        diskNode.setWsecS(Float.valueOf(temp[6]));
                        diskNode.setAvgrqSZ(Float.valueOf(temp[7]));
                        diskNode.setAvgquSZ(Float.valueOf(temp[8]));
                        diskNode.setAwait(Float.valueOf(temp[9]));
                        //diskNode.setrAWAIT(Float.valueOf(temp[10]));
                        //diskNode.setwAWAIT(Float.valueOf(temp[11]));
                        diskNode.setSvctm(Float.valueOf(temp[10]));
                        diskNode.setUtil(Float.valueOf(temp[11]));
                        infoDiskNode.add(diskNode);
                    }
                }
                infoIO.add(line);
            }
            if (ioUsage > 0) {
                infoBean.setDiskNode(infoDiskNode);
                System.out.println("-----------------------------------------------------------------------------------------------------------------------");
                System.out.println("最高磁盘IO使用率: " + formatFloat(ioUsage * 100) + "%");
                System.out.println("iostat -x -d 执行结果：");
                for (String str : infoIO) {
                    System.out.println(str);
                }
                infoBean.setiOUsage(ioUsage);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(in);
            IOUtils.close(pro);
        }
        return infoBean;
    }

    /**
     * @return bean
     * @Purpose:将"cat /proc/net/dev"中所有信息封装入bean参数。
     */
    public ResourceUsageInfoBean getNetUsage() {
        float netUsage = 0.0f;
        Process pro1 = null, pro2 = null;
        Runtime r = Runtime.getRuntime();
        BufferedReader in1 = null, in2 = null;
        try {
            String command = "cat /proc/net/dev";
            //第一次采集流量数据
            long startTime = System.currentTimeMillis();
            pro1 = r.exec(command);
            in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long inSize1 = 0, outSize1 = 0;
            int count = 0;
            while ((line = in1.readLine()) != null) {
                line = line.trim();
                String[] temp = line.split(":");
                if (++count >= 3) {//自己监控的网卡
                    //System.out.println(line);
                    temp[1] = temp[1].trim();
                    temp = temp[1].split("\\s+");
                    //截取掉网卡名
                    inSize1 += Long.parseLong(temp[0]);    //Receive bytes,单位为Byte
                    outSize1 += Long.parseLong(temp[8]);   //Transmit bytes,单位为Byte
                }
            }
            //第二次采集流量数据，采集网卡数据
            Thread.sleep(1000);
            long endTime = System.currentTimeMillis();
            pro2 = r.exec(command);
            in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long inSize2 = 0, outSize2 = 0;
            count = 0;
            long recieveBytes = 0;
            long recievePackets = 0;
            long recieveErrs = 0;
            long recieveDrop = 0;
            long recieveFifo = 0;
            long recieveFrame = 0;
            long recieveCompressed = 0;
            long recieveMulticast = 0;

            long transmitBytes = 0;
            long transmitPackets = 0;
            long transmitErrs = 0;
            long transmitDrop = 0;
            long transmitFifo = 0;
            long transmitColls = 0;
            long transmitCarrier = 0;
            long transmitCompressed = 0;
            while ((line = in2.readLine()) != null) {
                line = line.trim();
                String[] temp = line.split(":");
                if (++count >= 3) {//这里选择监控的网卡
                    //System.out.println(line);
                    temp[1] = temp[1].trim();
                    temp = temp[1].split("\\s+");
                    inSize2 += Long.parseLong(temp[0]);
                    outSize2 += Long.parseLong(temp[8]);

                    recieveBytes += Long.parseLong(temp[0]);
                    recievePackets += Long.parseLong(temp[1]);
                    recieveErrs += Long.parseLong(temp[2]);
                    recieveDrop += Long.parseLong(temp[3]);
                    recieveFifo += Long.parseLong(temp[4]);
                    recieveFrame += Long.parseLong(temp[5]);
                    recieveCompressed += Long.parseLong(temp[6]);
                    recieveMulticast += Long.parseLong(temp[7]);

                    transmitBytes += Long.parseLong(temp[8]);
                    transmitPackets += Long.parseLong(temp[9]);
                    transmitErrs += Long.parseLong(temp[10]);
                    transmitDrop += Long.parseLong(temp[11]);
                    transmitFifo += Long.parseLong(temp[12]);
                    transmitColls += Long.parseLong(temp[13]);
                    transmitCarrier += Long.parseLong(temp[14]);
                    transmitCompressed += Long.parseLong(temp[15]);
                }
            }
            if (inSize1 != 0 && outSize1 != 0 && inSize2 != 0 && outSize2 != 0) {
                infoBean.setReceiveBytes(recieveBytes);
                infoBean.setReceivePackets(recievePackets);
                infoBean.setReceiveErrs(recieveErrs);
                infoBean.setReceiveDrop(recieveDrop);
                infoBean.setReceiveFifo(recieveFifo);
                infoBean.setReceiveFrame(recieveFrame);
                infoBean.setReceiveCompressed(recieveCompressed);
                infoBean.setReceiveMulticast(recieveMulticast);
                infoBean.setTransmitBytes(transmitBytes);
                infoBean.setTransmitPackets(transmitPackets);
                infoBean.setTransmitErrs(transmitErrs);
                infoBean.setTransmitDrop(transmitDrop);
                infoBean.setTransmitFifo(transmitFifo);
                infoBean.setTransmitColls(transmitColls);
                infoBean.setTransmitCarrier(transmitCarrier);
                infoBean.setTransmitCompressed(transmitCompressed);

                float recTemp = (float) (recieveBytes) / 1024 / 1024;
                float traTemp = (float) (transmitBytes) / 1024 / 1024;
                infoBean.setReceiveTotalMB(formatFloat(recTemp));
                infoBean.setTransmitTotalMB(formatFloat(traTemp));
                infoBean.setTotalMB(formatFloat(recTemp+traTemp));
                System.out.println("下行总流量： " + infoBean.getReceiveTotalMB() + " MB");
                System.out.println("上行总流量： " + infoBean.getTransmitTotalMB() + " MB");
                System.out.println("总流量： " + infoBean.getTotalMB() + " MB");

                float interval = (float) (endTime - startTime) / 1000;

                float curRate = (float) (inSize2 - inSize1 + outSize2 - outSize1) / (1024 * 1024 * interval);
                infoBean.setNetSpeed(formatFloat(curRate));
                System.out.println("网口速度为: " + formatFloat(curRate) + " MB/s");

                netUsage = (curRate * 8) / TotalBandwidth;
                infoBean.setNetUsage(formatFloat(netUsage));
                System.out.println("网络带宽使用率为: " + formatFloat(netUsage*100) + " %");
            } else {
                System.out.println("莫得网络活动，速度为0");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(in1, in2);
            IOUtils.close(pro1, pro2);
        }
        return infoBean;
    }

    /**
     * 格式化float数字格式
     * decimalformat截取数字格式在趋近无穷小的时候出现无穷符号
     * 数字保留小数点后1位
     *
     */
    public static float formatFloat(float num){
        String numStr = Float.toString(num);
        if (numStr.contains(".")){
            String[] numSplit = numStr.split("\\.");
            numStr = numSplit[0] + "." + numSplit[1].substring(0,1);
            num = Float.valueOf(numStr);
        }else if(num == Float.NEGATIVE_INFINITY){
            num = 0f;
        }else if(num == Float.POSITIVE_INFINITY){
            num = 0f;
        }
        return num;
    }

    /**
     * 获取UpTime信息，
     *
     * @return bean
     * @pupose 获取uptime命令及"cat /proc/loadavg"的数据，封装入bean属性
     */
    public ResourceUsageInfoBean getUpTime() {
        String upTimeInfo = "";//控制台输出信息
        Process pro = null, pro2 = null;
        BufferedReader in = null, in2 = null;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "uptime";
            pro = r.exec(command);
            in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                upTimeInfo = line;
            }

            if (upTimeInfo != null) {
                //System.out.println("uptime:"+upTimeInfo);
                String[] upTime = upTimeInfo.split(",\\s+");
                String[] upTimeTemp = upTime[0].split("up\\s+");
                int length = upTime.length;
                infoBean.setCurrentSystemTime(upTimeTemp[0]);
                infoBean.setLivedTime(upTimeTemp[1]);

                //这个坑：有的时候，uptime输出的语句，会出现四个参数，而大多数的时候，都是三个。
                if (upTime[length - 4] != null && upTime[length - 4].endsWith("users")) {
                    infoBean.setUserNum(Integer.valueOf(upTime[length - 4].split("\\s+")[0]));
                }
                if (upTime[length - 3] != null && upTime[length - 3].startsWith("load")) {
                    infoBean.setLoadAverage(upTime[length - 3] + "," + upTime[length - 2] + "," + upTime[length - 1]);
                }
            }

            // 开始收集memory使用率
            Runtime r2 = Runtime.getRuntime();
            command = "cat /proc/loadavg";
            pro2 = r2.exec(command);
            in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            line = null;
            while ((line = in2.readLine()) != null) {
                String[] loadAvgInfo = line.split("\\s+");
                infoBean.setLoadAverage1(Float.valueOf(loadAvgInfo[0]));
                infoBean.setLoadAverage5(Float.valueOf(loadAvgInfo[1]));
                infoBean.setLoadAverage15(Float.valueOf(loadAvgInfo[2]));
                infoBean.setProccessStatus(loadAvgInfo[3]);
                infoBean.setRecentlyProccessID(Integer.valueOf(loadAvgInfo[4]));
                System.out.println("uptime: " + upTimeInfo);
                System.out.println("正在运行的进程数/系统进程数: " + infoBean.getProccessStatus()
                        + "       最近运行进程的ID: " + infoBean.getRecentlyProccessID());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(in, in2);
            IOUtils.close(pro, pro2);
        }
        return infoBean;
    }

    /**
     * 获取主机地址信息
     *
     * @return
     */
    public static InetAddress getHostLANAddress() {
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {
                        // 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            return jdkSuppliedAddress;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取本机的ip地址
     *
     * @return ip地址
     */
    public static String getLocalhostIp() {
        InetAddress inetAddress = getHostLANAddress();
        if (inetAddress != null) {
            return inetAddress.getHostAddress();
        }
        return "";
    }

    /**
     * 获取本机的hostname
     *
     * @return hostname
     */
    public static String getLocalhostName() {
        InetAddress inetAddress = getHostLANAddress();
        if (inetAddress != null) {
            return inetAddress.getHostName();
        }
        return "";
    }

    /**
     * 获取ip
     *
     * @return
     */
    public ResourceUsageInfoBean getIP() {
        infoBean.setIp(getLocalhostIp());
        infoBean.setHostName(getLocalhostName());
        System.out.println("loclahostIP: " + infoBean.getIp());
        System.out.println("loclahostName: " + infoBean.getHostName());
        return infoBean;
    }

    /**
     * 打印详情到控制台
     *
     * @return
     */
    public static ResourceUsageInfoBean getInfoBean() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        System.out.println("***********************************************************************************************************************");
        System.out.println("本次统计时间：" + dateFormat.format(date));
        SystemUtils usage = new SystemUtils();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getCpuUsage();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getMemoryUsage();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getNetUsage();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getIOUsage();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getUpTime();
        System.out.println("-----------------------------------------------------------------------------------------------------------------------");
        usage.getIP();
        System.out.println("***********************************************************************************************************************");
        return infoBean;

    }

    public static void main(String[] args) throws Exception {
        while (true) {
            ResourceUsageInfoBean infoBean2 = getInfoBean();
            Thread.sleep(1000);
            System.out.println(infoBean2);
        }
    }

}
